/*-------------------------------------------------------------------------
 *
 * nodeNamedtuplestorescan.c
 *	  处理NamedTuplestoreScan节点的例程。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/executor/nodeNamedtuplestorescan.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "executor/execdebug.h"
#include "executor/nodeNamedtuplestorescan.h"
#include "miscadmin.h"
#include "utils/queryenvironment.h"

static TupleTableSlot *fc_NamedTuplestoreScanNext(NamedTuplestoreScanState *fc_node);

/* ----------------------------------------------------------------
 *		NamedTuplestoreScanNext
 *
 *		这是 ExecNamedTuplestoreScan 的工作马
 * ----------------------------------------------------------------
 */
static TupleTableSlot * fc_NamedTuplestoreScanNext(NamedTuplestoreScanState *fc_node)
{
	TupleTableSlot *fc_slot;

	/* 我们故意不支持向后扫描。 */
	Assert(ScanDirectionIsForward(fc_node->ss.ps.state->es_direction));

	/*
	 * 从 tuplestore 获取下一个元组。如果没有更多元组，则返回 NULL。
	 */
	fc_slot = fc_node->ss.ss_ScanTupleSlot;
	tuplestore_select_read_pointer(fc_node->relation, fc_node->readptr);
	(void) tuplestore_gettupleslot(fc_node->relation, true, false, fc_slot);
	return fc_slot;
}

/*
 * NamedTuplestoreScanRecheck -- 用于在 EvalPlanQual 中重新检查元组的访问方法例程
 */
static bool fc_NamedTuplestoreScanRecheck(NamedTuplestoreScanState *fc_node, TupleTableSlot *fc_slot)
{
	
	return true;
}

/* ----------------------------------------------------------------
 *		ExecNamedTuplestoreScan(node)
 *
 *		顺序扫描 CTE 并返回下一个合格元组。
 *		我们调用 ExecScan() 例程，并传递适当的
 *		访问方法函数。
 * ----------------------------------------------------------------
 */
static TupleTableSlot * fc_ExecNamedTuplestoreScan(PlanState *fc_pstate)
{
	NamedTuplestoreScanState *fc_node = castNode(NamedTuplestoreScanState, fc_pstate);

	return ExecScan(&fc_node->ss,
					(ExecScanAccessMtd) fc_NamedTuplestoreScanNext,
					(ExecScanRecheckMtd) fc_NamedTuplestoreScanRecheck);
}


/* ----------------------------------------------------------------
 *		ExecInitNamedTuplestoreScan
 * ----------------------------------------------------------------
 */
NamedTuplestoreScanState *
ExecInitNamedTuplestoreScan(NamedTuplestoreScan *fc_node, EState *fc_estate, int fc_eflags)
{
	NamedTuplestoreScanState *fc_scanstate;
	EphemeralNamedRelation fc_enr;

	/* 检查不支持的标志 */
	Assert(!(fc_eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));

	/*
	 * NamedTuplestoreScan不应该有任何子节点。
	 */
	Assert(outerPlan(fc_node) == NULL);
	Assert(innerPlan(fc_node) == NULL);

	/*
	 * 为节点创建新的NamedTuplestoreScanState
	 */
	fc_scanstate = makeNode(NamedTuplestoreScanState);
	fc_scanstate->ss.ps.plan = (Plan *) fc_node;
	fc_scanstate->ss.ps.state = fc_estate;
	fc_scanstate->ss.ps.ExecProcNode = fc_ExecNamedTuplestoreScan;

	fc_enr = get_ENR(fc_estate->es_queryEnv, fc_node->enrname);
	if (!fc_enr)
		elog(ERROR, "executor could not find named tuplestore \"%s\"",
			 fc_node->enrname);

	Assert(fc_enr->reldata);
	fc_scanstate->relation = (Tuplestorestate *) fc_enr->reldata;
	fc_scanstate->tupdesc = ENRMetadataGetTupDesc(&(fc_enr->md));
	fc_scanstate->readptr =
		tuplestore_alloc_read_pointer(fc_scanstate->relation, EXEC_FLAG_REWIND);

	/*
	 * 新的读取指针从读取指针0复制其位置，读取指针0可以在任何地方，
	 * 所以需要显式地回卷它。
	 */
	tuplestore_select_read_pointer(fc_scanstate->relation, fc_scanstate->readptr);
	tuplestore_rescan(fc_scanstate->relation);

	/*
	 * XXX: 在完成时我们是否应该添加一个函数来释放该读取指针？
	 *
	 * 尝试过这样做，但在任何测试的情况下并没有改善性能或内存使用。
	 */

	/*
	 * 杂项初始化
	 *
	 * 为节点创建表达式上下文
	 */
	ExecAssignExprContext(fc_estate, &fc_scanstate->ss.ps);

	/*
	 * 扫描元组类型被指定用于tuplestore。
	 */
	ExecInitScanTupleSlot(fc_estate, &fc_scanstate->ss, fc_scanstate->tupdesc,
						  &TTSOpsMinimalTuple);

	/*
	 * 初始化结果类型和投影。
	 */
	ExecInitResultTypeTL(&fc_scanstate->ss.ps);
	ExecAssignScanProjectionInfo(&fc_scanstate->ss);

	/*
	 * 初始化子表达式
	 */
	fc_scanstate->ss.ps.qual =
		ExecInitQual(fc_node->scan.plan.qual, (PlanState *) fc_scanstate);

	return fc_scanstate;
}

/* ----------------------------------------------------------------
 *		ExecEndNamedTuplestoreScan
 *
 *		释放通过C例程分配的任何存储。
 * ----------------------------------------------------------------
 */
void ExecEndNamedTuplestoreScan(NamedTuplestoreScanState *fc_node)
{
	/*
	 * 释放exprcontext
	 */
	ExecFreeExprContext(&fc_node->ss.ps);

	/*
	 * 清空元组表
	 */
	if (fc_node->ss.ps.ps_ResultTupleSlot)
		ExecClearTuple(fc_node->ss.ps.ps_ResultTupleSlot);
	ExecClearTuple(fc_node->ss.ss_ScanTupleSlot);
}

/* ----------------------------------------------------------------
 *		ExecReScanNamedTuplestoreScan
 *
 *		重新扫描关系。
 * ----------------------------------------------------------------
 */
void ExecReScanNamedTuplestoreScan(NamedTuplestoreScanState *fc_node)
{
	Tuplestorestate *fc_tuplestorestate = fc_node->relation;

	if (fc_node->ss.ps.ps_ResultTupleSlot)
		ExecClearTuple(fc_node->ss.ps.ps_ResultTupleSlot);

	ExecScanReScan(&fc_node->ss);

	/*
	 * 回卷我自己的指针。
	 */
	tuplestore_select_read_pointer(fc_tuplestorestate, fc_node->readptr);
	tuplestore_rescan(fc_tuplestorestate);
}
